import numpy
import scipy
#from scipy import interpolate

from Bases import BaseObject, setID
from DeviceSystem.Groups.Group import GroupBase

class BaseController(BaseObject):
    _saved_attributes = ['id', 'name', 'src_attr']
    def __init__(self, **kwargs):
        super(BaseController, self).__init__(**kwargs)
        self.register_signal('value_update', 'settings_changed')
        if 'deserialize' not in kwargs:
            self.id = setID(kwargs.get('id'))
            self.name = kwargs.get('name')
            self.src_attr = kwargs.get('src_attr')
        self.src_object = kwargs.get('src_object')
        
        self.obj_scale_factor = kwargs.get('obj_scale_factor', 
                                           getattr(self.src_object, 'value_scale', 255))
        self.value_wrap_around = kwargs.get('value_wrap_around', 
                                            getattr(self.src_object, 'value_wrap_around', False))
        for key in ['obj_scale_factor', 'value_wrap_around']:
            val = getattr(self, key)
            if type(val) == dict:
                newval = val.get(self.src_attr)
                if newval is not None:
                    setattr(self, key, newval)
        #if type(self.obj_scale_factor) == dict:
        #    scale = self.obj_scale_factor.get(self.src_attr)
        #    if scale is not None:
        #        self.obj_scale_factor = scale
        
    
    def on_interval(self, timeV):
        value = self.calclulate_value(timeV)
        if value is not False and self.src_object is not None:
            setattr(self.src_object, self.src_attr, value * self.obj_scale_factor)
    
    def store_value(self, *args, **kwargs):
        pass
    
    def calclulate_value(self, timeV):
        pass
        
    def get_object_value(self):
        return getattr(self.src_object, self.src_attr)
        
class KeyframeController(BaseController):
    _saved_class_name = 'KeyframeController'
    _saved_attributes = ['hook_style', 'keyframes']
    def __init__(self, **kwargs):
        super(KeyframeController, self).__init__(**kwargs)
        if 'deserialize' not in kwargs:
            self.hook_style = kwargs.get('hook_style', 'linear')
            self.keyframe_array = None
            self.keyframes = {}
            keyframes = kwargs.get('keyframes', {})
            self.add_keyframes(keyframes)
        self.update_keyframe_array()
        
    def on_settings_changed(self, **kwargs):
        d = kwargs.get('keyframes')
        if d:
            self.add_keyframes(d)
            
    def store_value(self, timeV, value=None):
        if value is not None:
            self.add_keyframes({timeV:value / self.obj_scale_factor})
        else:
            self.store_current_value(timeV)
        
    def store_current_value(self, timeV):
        value = self.get_object_value() / self.obj_scale_factor
        self.add_keyframes({timeV:value})
        
    def add_keyframes(self, d):
        self.keyframes.update(d)
        self.update_keyframe_array()
        #self.spline = interpolate.BivariateSpline(self.keyframe_array[0], self.keyframe_array[1])
        self.emit('settings_changed', keyframes=self.keyframes)
        
    def update_keyframe_array(self):
        keys = self.keyframes.keys()
        keys.sort()
        l1 = [float(key) for key in keys]
        l2 = [float(self.keyframes.get(key)) for key in keys]
        if self.value_wrap_around:
            for i, val in enumerate(l2):
                next = i + 1
                if i == len(l2) - 1:
                    break
                    next = 0
                if val > l2[next]:
                    if val - l2[next] > .5:
                        l2[next] += 1.
                else:
                    if l2[next] - val > .5:
                        l2[i] += 1.
            #print 'wrap around: old=%s, new=%s' % ([float(self.keyframes.get(key)) for key in keys], l2)
        self.keyframe_array = numpy.array([l1, l2])
        flag = True
        if len(l2) == 0 or l2.count(l2[0]) == len(l2):
            flag = False
        self.does_change = flag
        
    def calclulate_value(self, timeV):
        val = numpy.interp(timeV, self.keyframe_array[0], self.keyframe_array[1])
        if self.value_wrap_around and val > 1.:
            print self.src_object, 'wrapping val: ', val
            val -= 1.
        return val
        
class FunctionalController(BaseController):
    _saved_class_name = 'FunctionalController'
    _saved_attributes = ['expression']
    def __init__(self, **kwargs):
        super(FunctionalController, self).__init__(**kwargs)
        if 'deserialize' not in kwargs:
            exp = kwargs.get('expression', 'value=timeV')
            if '=' in exp:
                exp = exp.split('=')[1]
            self.expression = exp
        self.function = kwargs.get('function', self._default_function)
    def on_settings_changed(self, **kwargs):
        exp = kwargs.get('expression')
        if exp:
            self.expression = exp
            
    @property
    def expression(self):
        return self._expression
    @expression.setter
    def expression(self, value):
        self._expression = value
        self.emit('settings_changed', expression=value)
        
    def _default_function(self, timeV):
        #x = timeV
        return eval(self.expression)
        
    def calclulate_value(self, timeV):
        value = self.function(timeV)
        return value

class MultiController(BaseController):
    _saved_attributes = ['controller_type']
    _saved_child_objects = ['controllers']
    _saved_child_classes = [KeyframeController, FunctionalController]
    def __init__(self, **kwargs):
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        super(MultiController, self).__init__(**kwargs)
        if 'deserialize' not in kwargs:
            self.controllers = {}
            self.controller_type = kwargs.get('controller_type')
            cls = controllerTypes.get(self.controller_type)
            for key in getattr(self.src_object, self.src_attr).iterkeys():
                c_kwargs = kwargs.copy()
                c_kwargs.update({'src_attr':key, 'id':key})
                c = cls(**c_kwargs)
                self.controllers.update({c.id:c})
    @property
    def expression(self):
        d = {}
        for key, val in self.controllers.iteritems():
            d.update({key:val.expression})
        return d
    @expression.setter
    def expression(self, value):
        for key, val in value.iteritems():
            c = self.controllers.get(key)
            if c:
                c.expression = val
                
    def store_value(self, timeV, value=None):
        if value is None:
            value = {}
        for c in self.controllers.itervalues():
            c.store_value(timeV, value.get(c.id))
            
    def on_interval(self, timeV):
        for c in self.controllers.itervalues():
            c.on_interval(timeV)
            
    def on_settings_changed(self, **kwargs):
        pass
        #for c in self.controllers.itervalues():
        #    c.on_settings_changed(**kwargs)
    

controllerTypes = {'Keyframe':KeyframeController, 'Functional':FunctionalController, 'Multi':MultiController}
